package tony.web.auth.jwt

import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm.HMAC256
import com.auth0.jwt.exceptions.JWTVerificationException
import com.auth0.jwt.interfaces.DecodedJWT
import tony.core.PROJECT_GROUP
import tony.core.SpringContexts
import tony.core.TOKEN_HEADER_NAME
import tony.core.utils.getLogger
import tony.core.utils.ifNullOrBlank
import tony.web.WebContext
import tony.web.WebContext.getOrPut
import tony.web.WebSession
import tony.web.exception.UnauthorizedException

/**
 * jwt 实现的session.
 *
 * @author tangli
 * @date 2023/05/25 19:17
 */
public open class JwtWebSession : WebSession {
    private val logger = getLogger()

    protected val token: DecodedJWT
        get() =
            WebContext.current.getOrPut("token") {
                val jwtTokenString =
                    WebContext
                        .request
                        .getHeader(TOKEN_HEADER_NAME)
                        .ifNullOrBlank()
                try {
                    JWT
                        .require(HMAC256(SpringContexts.Env.getProperty("$PROJECT_GROUP.web.auth.jwt.secret", "")))
                        .build()
                        .verify(jwtTokenString)
                } catch (_: JWTVerificationException) {
                    logger.warn("Jwt Token($jwtTokenString) verify failed.")
                    throw UnauthorizedException("请登录")
                }
            }

    override val userId: String
        get() =
            WebContext.current.getOrPut("userId") {
                token.getClaim("userId")?.asString() ?: throw UnauthorizedException("请登录")
            }

    override val unauthorizedException: UnauthorizedException?
        get() =
            try {
                token
                null
            } catch (e: UnauthorizedException) {
                e
            }
}
